package cn.xzqwjw.taskmanager.service.impl;

import cn.xzqwjw.taskmanager.common.customEnum.ResponseCodeEnum;
import cn.xzqwjw.taskmanager.common.exception.CustomException;
import cn.xzqwjw.taskmanager.domain.pojo.SysRole;
import cn.xzqwjw.taskmanager.domain.pojo.SysRolePurview;
import cn.xzqwjw.taskmanager.domain.vo.ResponseVo;
import cn.xzqwjw.taskmanager.repository.SysRoleMapper;
import cn.xzqwjw.taskmanager.service.SysRolePurviewService;
import cn.xzqwjw.taskmanager.service.SysRoleService;
import cn.xzqwjw.taskmanager.utils.CommonUtil;
import cn.xzqwjw.taskmanager.utils.JsonUtil;
import cn.xzqwjw.taskmanager.utils.MyListUtil;
import cn.xzqwjw.taskmanager.utils.MyMapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author rush
 */
@Service("SysRoleService")
@Transactional(rollbackFor = Exception.class)
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole>
    implements SysRoleService {

  private final SysRolePurviewService rolePurviewService;

  @Autowired
  public SysRoleServiceImpl(
      SysRolePurviewService rolePurviewService) {
    this.rolePurviewService = rolePurviewService;
  }

  @Override
  public String add(String paramsJson) {
    CommonUtil.checkNull(paramsJson);
    Map<String, ?> paramsMap = JsonUtil.json2Obj(paramsJson, Map.class);
    SysRole sysRole = getRole(paramsMap);
    List<Integer> purviewIds = getPurviewIds(paramsMap);
    if (!save(sysRole)) {
      throw new CustomException(ResponseCodeEnum.ERROR_INSERT);
    }
    // id是自增，用getId即可得到save后的id值
    // 添加角色对应的所有权限
    if (addPurviewIdsByRoleId(sysRole.getId(), purviewIds)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_CREATED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_INSERT);
    }
  }

  @Override
  public String delById(Integer id) {
    if (removeById(id)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_DELETED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_DELETE);
    }
  }

  @Override
  public String modifyAll(String paramsJson) {
    CommonUtil.checkNull(paramsJson);
    Map<String, ?> paramsMap = JsonUtil.json2Obj(paramsJson, Map.class);
    SysRole sysRole = getRole(paramsMap);
    List<Integer> purviewIds = getPurviewIds(paramsMap);
    if (!updateById(sysRole)) {
      throw new CustomException(ResponseCodeEnum.ERROR_UPDATE);
    }
    if (addPurviewIdsByRoleId(sysRole.getId(), purviewIds)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_UPDATED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_UPDATE);
    }
  }

  @Override
  public String patchEnabled(String paramsJson) {
    CommonUtil.checkNull(paramsJson);
    Map<?, ?> paramsMap = JsonUtil.json2Obj(paramsJson, Map.class);
    Integer idRole = MyMapUtil.getValueInt(paramsMap, "RoleId", true);
    Boolean flagEnabled = MyMapUtil.getValueBool(paramsMap, "FlagEnabled", true);
    UpdateWrapper<SysRole> wrapper = new UpdateWrapper<>();
    wrapper.set("flag_enabled", flagEnabled).eq("id", idRole);
    if (update(wrapper)) {
      return JsonUtil.obj2Json(ResponseVo.success());
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_UPDATE);
    }
  }

  @Override
  public String queryById(Integer id) {
    SysRole sysRole = getById(id);
    if (Objects.nonNull(sysRole)) {
      return JsonUtil.obj2Json(ResponseVo.success(sysRole));
    } else {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
  }

  @Override
  public String listAll() {
    QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
    wrapper.eq("flag_system", false);
    return JsonUtil.obj2Json(ResponseVo.success(list(wrapper)));
  }

  @Override
  public String checkLabel(String name, Integer id) {
    Map<String, Boolean> returnMap = new HashMap<>(16);
    returnMap.put("IsAdded", isAddedByName(name, id));
    return JsonUtil.obj2Json(ResponseVo.success(returnMap));
  }

  @Override
  public String checkCode(String code, Integer id) {
    Map<String, Boolean> returnMap = new HashMap<>(16);
    returnMap.put("IsAdded", isAddedByCode(code, id));
    return JsonUtil.obj2Json(ResponseVo.success(returnMap));
  }

  /**
   * 添加或修改角色时从前端传入的参数中获取角色
   */
  private SysRole getRole(Map<String, ?> paramsMap) {
    SysRole sysRole = parseRole(paramsMap);
    if (Objects.isNull(sysRole)) {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    // 1、判断此角色的名称是否已添加
    if (isAddedByName(sysRole.getLabel(), sysRole.getId())) {
      throw new CustomException(ResponseCodeEnum.UNPROCESSABLE_ENTITY);
    }
    // 2、判断此角色的代码是否已添加
    if (isAddedByCode(sysRole.getCode(), sysRole.getId())) {
      throw new CustomException(ResponseCodeEnum.UNPROCESSABLE_ENTITY);
    }
    return sysRole;
  }

  /**
   * 添加或修改角色时从前端传入的参数中获取角色所对应的权限id数组
   */
  private List<Integer> getPurviewIds(Map<String, ?> paramsMap) {
    List<Integer> purviewIds = parsePurviewIds(paramsMap);
    // 判断此角色所拥有的权限数组是否为空
    if (CollectionUtils.isEmpty(purviewIds)) {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    return purviewIds;
  }

  /**
   * 添加/编辑角色时，验证此角色 name 是否已添加，编辑时应排除当前正在编辑的角色
   *
   * @param label 角色名称
   * @param id    角色id
   * @return 是否已添加
   */
  private boolean isAddedByName(String label, Integer id) {
    QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
    if (id > 0) {
      wrapper.eq("label", label).ne("id", id);
    } else {
      wrapper.eq("label", label);
    }
    return getOne(wrapper, false) != null;
  }

  /**
   * 添加/编辑角色时，验证此角色 code 是否已添加，编辑时应排除当前正在编辑的角色
   *
   * @param code 角色代码
   * @param id   角色id
   * @return 是否已添加
   */
  private boolean isAddedByCode(String code, Integer id) {
    QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
    if (id > 0) {
      wrapper.eq("code", code).ne("id", id);
    } else {
      wrapper.eq("code", code);
    }
    return getOne(wrapper, false) != null;
  }

  /**
   * 添加或修改此角色下的所有权限
   * 无论是添加还是修改都是先删除已有的再重新添加新的
   *
   * @param idRole     角色id
   * @param purviewIds 此角色所拥有的权限id数组
   * @return 是否添加成功
   */
  private boolean addPurviewIdsByRoleId(int idRole, List<Integer> purviewIds) {
    // 1、先把roleId下的已有权限都删除
    QueryWrapper<SysRolePurview> wrapper = new QueryWrapper<>();
    wrapper.eq("id_role", idRole)
        // 为了去除sql安全错误（不允许不带主键的更新操作）添加此条规则
        .gt("id", 0);
    rolePurviewService.remove(wrapper);
    // 2、批量向角色权限表里添加记录
    List<SysRolePurview> listRolePurview = new ArrayList<>();
    SysRolePurview rolePurview;
    for (int idPurview : purviewIds) {
      rolePurview = new SysRolePurview();
      rolePurview.setIdRole(idRole);
      rolePurview.setIdPurview(idPurview);
      listRolePurview.add(rolePurview);
    }
    return rolePurviewService.saveBatch(listRolePurview);
  }

  /**
   * 解析得到Role对象
   */
  private SysRole parseRole(Map<String, ?> paramsMap) {
    try {
      return MyMapUtil.getValuePojo(paramsMap, "SysRole", true, SysRole.class);
    } catch (Exception e) {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
  }

  /**
   * 解析得到权限数组
   */
  private List<Integer> parsePurviewIds(Map<String, ?> paramsMap) {
    Object obj = MyMapUtil.getValueObject(paramsMap, "PurviewIds", true);
    if (!(obj instanceof ArrayList)) {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
    // 安全的转换方式
    List<String> list = MyListUtil.castList(obj, String.class);
    List<Integer> returnList = new ArrayList<>();
    for (String item : list) {
      returnList.add(Integer.parseInt(item));
    }
    return returnList;
  }

}
